﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace Sofire.DataComm.Net.Async
{
    /*
     * 大容量数据收发约定
	1、客户端通过 Full 模式发送大容量数据的基础信息至服务端，如：文件名。
	2、服务端收到通知，并在服务端注册一个标志，表示下一次 Once 模式即将接收的大容量数据。
	3、客户端通过 Once 模式开始发送大容量数据。
	4、服务端依次接收客户端的数据，并在不断触发 Once 模式的 Receive 事件。
     */

    /// <summary>
    /// 异步套接字发送数据后发生的事件参数。
    /// </summary>
    public class AsyncSocketReceiveEventArgs : AsyncSocketEventArgs
    {
        private ReceiveMode _Mode;
        /// <summary>
        /// 获取数据接收的模式。
        /// </summary>
        public ReceiveMode Mode
        {
            get
            {
                return this._Mode;
            }
        }

        private int _TotalLength;
        /// <summary>
        /// 获取数据的总长度。
        /// </summary>
        public int TotalLength
        {
            get
            {
                return this._TotalLength;
            }
        }

        private int _ReadLength;
        /// <summary>
        /// 获取已读取的数据长度。
        /// </summary>
        public int ReadLength
        {
            get
            {
                return this._ReadLength;
            }
        }

        private byte[] _Buffer;
        /// <summary>
        /// 获取接收的数据缓冲区。
        /// </summary>
        public byte[] Buffer
        {
            get
            {
                return this._Buffer;
            }
        }

        private int _Offset;
        /// <summary>
        /// 获取数据缓冲区中操作开始位置处的偏移量，以字节为单位。
        /// </summary>
        public int Offset
        {
            get
            {
                return this._Offset;
            }
        }

        private int _Count;
        /// <summary>
        /// 获取可在缓冲区中发送或接收的最大数据量（以字节为单位）。
        /// </summary>
        public int Count
        {
            get
            {
                return this._Count;
            }
        }

        /// <summary>
        /// 获取一个值，指示是否为第一次接收（通常用于 <see cref="Sofire.DataComm.Net.Async.ReceiveMode.Once"/> 模式）。
        /// </summary>
        public bool IsFirstTime
        {
            get
            {
                return this._TotalLength == this._Count;
            }
        }

        /// <summary>
        /// 获取一个值，指示数据接收是否完成（通常用于 <see cref="Sofire.DataComm.Net.Async.ReceiveMode.Once"/> 模式）。
        /// </summary>
        public bool IsCompleted
        {
            get
            {
                return this._TotalLength == this._ReadLength;
            }
        }

        private IRemote _Remote;
        /// <summary>
        /// 获取正在连接的远程端。
        /// </summary>
        public IRemote Remote
        {
            get
            {
                return this._Remote;
            }
        }

        internal AsyncSocketBase _SocketBase;

        /// <summary>
        /// 初始化 <see cref="Sofire.DataComm.Net.Async.AsyncSocketReceiveEventArgs"/> 的新实例。
        /// </summary>
        /// <param name="asyncEventArgs">当前事件参数关联的 <see cref="System.Net.Sockets.SocketAsyncEventArgs"/>。</param>
        public AsyncSocketReceiveEventArgs(SocketAsyncEventArgs asyncEventArgs) : base(asyncEventArgs) { }

        internal void SetBuffer(ReceiveMode mode, byte[] buffer, int offset, int count, IRemote remote)
        {
            this.SetBuffer(mode, count, count, buffer, 0, count, remote);
        }

        internal void SetBuffer(ReceiveMode mode, int totalLength, int readLength, byte[] buffer, int offset, int count, IRemote remote)
        {
            this._Mode = mode;
            this._TotalLength = totalLength;
            this._ReadLength = readLength;
            this._Buffer = buffer;
            this._Offset = offset;
            this._Count = count;
            this._Remote = remote;
        }

        /// <summary>
        /// 根据当前缓冲区数据，获取一个 <see cref="System.Int32"/>  和 <see cref="System.String"/> 值。
        /// </summary>
        /// <param name="intValue">一个整形值。</param>
        /// <param name="stringValue">一个字符串值。</param>
        public void GetValue(out int intValue, out string stringValue)
        {
            if(this._SocketBase == null) throw new ArgumentNullException("AsyncSocketbase");
            if(this._Mode != ReceiveMode.Full) throw new NotSupportedException("当前方法仅支持 Sofire.DataComm.Net.Async.MessageReceiveMode.Full 模式。");
            int offset = this._Offset;
            intValue = BufferConvert.ReadInt32(this._Buffer, ref offset);
            stringValue = this._SocketBase.DefaultEncoding.GetString(this._Buffer, offset, this._Count - 4);
        }

        /// <summary>
        /// 根据当前缓冲区数据，获取一个 <see cref="System.String"/> 值。
        /// </summary>
        /// <returns>返回 <see cref="System.String"/> 值。</returns>
        public string GetString()
        {
            return this.GetString(this._Offset, this._Count);
        }

        /// <summary>
        /// 根据当前缓冲区数据，获取一个 <see cref="System.String"/> 值。
        /// </summary>
        /// <param name="offset">开始位置处的偏移量，以字节为单位。</param>
        /// <param name="count">最大数据量（以字节为单位）。</param>
        /// <returns>返回 <see cref="System.String"/> 值。</returns>
        public string GetString(int offset, int count)
        {
            return this._SocketBase.DefaultEncoding.GetString(this._Buffer, offset, count);
        }

        /// <summary>
        /// 根据当前缓冲区数据，获取一个 <typeparamref name="TEntity"/> 对象实例。
        /// </summary>
        /// <typeparam name="TEntity">实例的数据类型。</typeparam>
        /// <returns>返回一个对象类型的实例。</returns>
        public TEntity GetEntity<TEntity>()
        {
            var r = AsyncSocketBase.DefaultFormatter.Read<TEntity>(new System.IO.MemoryStream(this._Buffer, this._Offset, this._Count));
            if(r.IsFailed) throw r.Exception;
            return r.Value;
        }

        /// <summary>
        /// 清空缓冲区的数据。
        /// </summary>
        public void Clear()
        {
            this._Remote = null;
            this._SocketBase = null;
            this._Buffer = null;
        }
    }

    /// <summary>
    /// 异步套接字接收数据后发生的事件委托。
    /// </summary>
    /// <param name="sender">事件对象。</param>
    /// <param name="e">事件参数。</param>
    public delegate void AsyncSocketReceiveEventHandler(object sender, AsyncSocketReceiveEventArgs e);
}
